#!/usr/bin/python
# -*- coding: UTF-8 -*-
 
import re

reg_access_dict = {"read-write": "WR", "read-only": "RO", "write-only": "WO"}


def line_str_pre(excel_str):
    str1 = re.sub(r'\\n', '\n', excel_str.strip())
    str2 = re.sub(r'\n[ |\t]+', '\n', str1)
    return str2

def add_reserve_field(filed_paras_dict = {}):
    bit_cover = ['0'] * 32
    for key in filed_paras_dict.keys():
        for cnt in range(key, key + filed_paras_dict[key][0]):
            bit_cover[cnt] = '1'
    
    str_cover = ''.join(bit_cover)
    pos_offset = 0
    bit_res_offset_width = []
    while True:
        ret = re.search('0+',str_cover) 
        if ret:
            bit_res_offset_width.append([ret.span()[0] + pos_offset, ret.span()[1] + pos_offset])
            str_cover = str_cover[ret.span()[1]:]
            pos_offset = ret.span()[1] + pos_offset
        else:
            break

    # key： offset，  value: field_width, Bits, name, access, descript
    for item in bit_res_offset_width:
        filed_paras_dict[item[0]] = (item[1] - item[0]), str(item[1] - 1) + ":" + str(item[0]), 'Reserve', 'RO', 'Reserve.'
    
    return sorted(filed_paras_dict.items(), reverse=True)

def get_peri_regs_info(regs):
    reg_cnt = 0
    reg_desp_dict = {}
    for reg in  regs:
        reg_name = reg.getElementsByTagName('name')[0].childNodes[0].data
        if reg.getElementsByTagName('description').length != 0:
            pre_reg_descript = reg.getElementsByTagName('description')[0].childNodes[0].data
        else:
            pre_reg_descript = ""
            print("reg description err: " +reg_name)
        reg_descript = line_str_pre(pre_reg_descript)

        if reg.getElementsByTagName('resetValue').length != 0:
            raw_reset_val = reg.getElementsByTagName('resetValue')[0].childNodes[0].data
            reset_val = str('0x{:08X}'.format(int(raw_reset_val, 16))).upper().replace('X', 'x')
        else:
            reset_val = '0x00000000'
            print(reg_name + "reset value loss")
       
        if reg.getElementsByTagName('addressOffset')[0].childNodes == []:
            offset = '0x0000'
        else:
            raw_offset = reg.getElementsByTagName('addressOffset')[0].childNodes[0].data
            offset = str('0x{:04X}'.format(int(raw_offset, 16))).upper().replace('X', 'x')

        if reg.getElementsByTagName('access').length != 0:
            reg_access = reg.getElementsByTagName('access')[0].childNodes[0].data
        else:
            reg_access = 'read-only'
            print(reg_name + " access loss")

        
        # name， offset
        dim_list = []
        if "%s" in  reg_name:
            dim_inc = int(reg.getElementsByTagName('dimIncrement')[0].childNodes[0].data, 16)

            if reg.getElementsByTagName('dimIndex').length != 0:
                dim_idx_str = reg.getElementsByTagName('dimIndex')[0].childNodes[0].data
                start_pos = int(dim_idx_str.split("-", 1)[0])
                end_pos = int(dim_idx_str.split("-", 1)[1])
                for idx in range(start_pos, end_pos + 1):
                    dim_list.append((re.sub('%s', str(idx), reg_name), str('0x{:04X}'.format(int(offset, 16) + dim_inc * idx )).upper().replace('X', 'x') ))

            if reg.getElementsByTagName('dimArrayIndex').length != 0:
                dim_idx_str = reg.getElementsByTagName('dimArrayIndex')[0].childNodes[0].data
                idx_str_list = dim_idx_str.split(',')
                for idx in range(0, len(idx_str_list)):
                    dim_list.append((re.sub('%s', idx_str_list[idx], reg_name), str('0x{:04X}'.format(int(offset, 16) + dim_inc * idx )).upper().replace('X', 'x') ))

            elif reg.getElementsByTagName('dimIndex').length != 0:
                dim_idx_str = reg.getElementsByTagName('dimIndex')[0].childNodes[0].data
                start_pos = int(dim_idx_str.split("-", 1)[0])
                end_pos = int(dim_idx_str.split("-", 1)[1])
                for idx in range(start_pos, end_pos + 1):
                    dim_list.append((re.sub('%s', str(idx), reg_name), str('0x{:04X}'.format(int(offset, 16) + dim_inc * idx )).upper().replace('X', 'x') ))
            else:
                dim_len = reg.getElementsByTagName('dim')[0].childNodes[0].data
                for idx in range(0, int(dim_len)):
                    dim_list.append((re.sub('%s', str(idx), reg_name), str('0x{:04X}'.format(int(offset, 16) + dim_inc * idx )).upper().replace('X', 'x') ))

            # print(dim_list)
            # print(reg_name)
    

        fields = reg.getElementsByTagName('field')
        # key： offset，  value: field_width, Bits, name, access, descript
        filed_paras_dict = {}
        for field in fields:
            field_name = field.getElementsByTagName('name')[0].childNodes[0].data
            if field.getElementsByTagName('description').length != 0:
                pre_field_desp = field.getElementsByTagName('description')[0].childNodes[0].data
            else:
                pre_field_desp = ""
                # print("field description err: " +reg_name + "->" + field_name)

            enum_desp = ""
            if field.getElementsByTagName('enumeratedValue').length != 0:
                enums = field.getElementsByTagName('enumeratedValue')
                for enum_node in enums:
                    name = enum_node.getElementsByTagName('name')[0].childNodes[0].data
                    val = enum_node.getElementsByTagName('value')[0].childNodes[0].data
                    if enum_node.getElementsByTagName('description').length != 0:
                        desp = ". " + enum_node.getElementsByTagName('description')[0].childNodes[0].data
                    else:
                        desp = ""
                    enum_desp += "\n" + val + ": " + name + desp
            # else:
            #     print(field_name + " enum err")
            pre_field_desp += enum_desp
            field_desp = line_str_pre(pre_field_desp)

        
            if field.getElementsByTagName('bitOffset').length != 0 and field.getElementsByTagName('bitWidth').length != 0:
                field_offset = int(field.getElementsByTagName('bitOffset')[0].childNodes[0].data)
                field_width = int(field.getElementsByTagName('bitWidth')[0].childNodes[0].data)
            elif field.getElementsByTagName('bitRange').length != 0:
                str_b_range = str(field.getElementsByTagName('bitRange')[0].childNodes[0].data)[1:-1]
                max_val = max(int(str_b_range.split(":")[0]), int(str_b_range.split(":")[1]))
                min_val = min(int(str_b_range.split(":")[0]), int(str_b_range.split(":")[1]))
                field_offset = min_val
                field_width = max_val - min_val + 1
            elif field.getElementsByTagName('msb').length != 0 and field.getElementsByTagName('lsb').length != 0:
                max_val = int(field.getElementsByTagName('msb')[0].childNodes[0].data) 
                min_val = int(field.getElementsByTagName('lsb')[0].childNodes[0].data) 
                field_offset = min_val
                field_width = max_val - min_val + 1
            else:
                print("field bit err")

            bits_len = str(field_width + field_offset - 1) + ":" + str(field_offset)
            if field.getElementsByTagName('access').length != 0:
                filed_access = field.getElementsByTagName('access')[0].childNodes[0].data
            else:
                filed_access = reg_access

            filed_paras_dict[field_offset] = [field_width, bits_len, field_name, reg_access_dict[filed_access], field_desp]
        filed_paras_sort_tuple = add_reserve_field(filed_paras_dict)

        # key： cnt  value: name, offset, reset, descript, access, field_tuple
        if len(dim_list) == 0: 
            reg_desp_dict[reg_cnt] = reg_name, offset, reset_val, reg_descript, reg_access, filed_paras_sort_tuple
            reg_cnt = reg_cnt + 1
        else:
            for item in dim_list:
                reg_desp_dict[reg_cnt] = item[0], item[1], reset_val, reg_descript, reg_access, filed_paras_sort_tuple
                reg_cnt = reg_cnt + 1

    return reg_desp_dict

def get_reg_msk(field_tuple, access):
    bit_cover = ['0'] * 32
    for item in field_tuple:
        start_pos = int(item[1][1].split(':', 1)[1])
        end_pos = int(item[1][1].split(':', 1)[0])
        if item[1][3] == access:
            for cnt in range(start_pos, end_pos + 1):
                bit_cover[cnt] = '1'
    
    bit_num = int(''.join(reversed(bit_cover)), 2)
    hex_num = hex(bit_num)
    return hex_num



